package com.tsmti.core.common.service.impl;

import com.tsmti.core.common.dao.BaseDao;
import com.tsmti.core.common.data.DuplicateValid;
import com.tsmti.core.common.query.data.Page;
import com.tsmti.core.common.query.data.PageImpl;
import com.tsmti.core.common.query.data.Pageable;
import com.tsmti.core.common.query.data.Queryable;
import com.tsmti.core.common.query.parse.CriteriaParse;
import com.tsmti.core.common.query.parse.QueryParse;
import com.tsmti.core.common.query.utils.QueryableConvertUtils;
import com.tsmti.core.common.service.BaseService;
import com.tsmti.core.util.RedisUtils;
import com.tsmti.core.util.ReflectionUtils;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.DetachedCriteria;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Title：PimsSystem
 * Class：com.tsmti.core.base
 * Comapny:
 *
 * @author：zcw
 * @version：2.5 CreateTime：2017/12/29 15:56
 * Modify log:
 * Description：
 */
@Service("baseService")
@Transactional(rollbackFor = Exception.class)
public  class BaseServiceImpl<T extends Serializable> implements BaseService<T> {
    protected Logger logger = LoggerFactory.getLogger(getClass());
    private final static String QUERYTYPE_TABLE = "queryType";

    @Resource(name = "baseDao")
    protected BaseDao baseDao;
    protected Class<T> entityClass;

    public BaseServiceImpl() {
        this.entityClass = ReflectionUtils.getSuperGenericType(getClass());
    }

    @Override
    public T save(T entity) {
        return baseDao.save(entity);
    }

    @Override
    public void saveAll(List<T> entitys) {
        baseDao.saveAll(entitys);
    }

    @Override
    public List<T> saveList(List<T> entitys) {
        return baseDao.saveList(entitys);
    }

    @Override
    public void saveOrUpdate(T entity) {
        baseDao.saveOrUpdate(entity);
    }

    @Override
    public void update(T entity) {
        baseDao.update(entity);
    }

    @Override
    public T load(Serializable id) {
        return baseDao.load(id,entityClass);
    }

    @Override
    public T get(Serializable id) {
        return baseDao.get(id,entityClass);
    }

    @Override
    public T get(String propertyName, Object value) {
        return baseDao.get(propertyName,value,entityClass);
    }

    @Override
    public Boolean exists(Serializable id) {
        return baseDao.exists(id,entityClass);
    }

    @Override
    public Long count() {
        return baseDao.count(entityClass);
    }

    @Override
    public Long count(DetachedCriteria detachedCriteria) {
        return baseDao.count(detachedCriteria);
    }

    @Override
    public Long count(Criterion... criterions) {
        return baseDao.count(entityClass,criterions);
    }

    @Override
    @Transactional(readOnly = true)
    public List<T> list() {
        return baseDao.list(entityClass);
    }

    @Override
    @Transactional(readOnly = true)
    public List<T> list(String propertyName, Object value) {
        return baseDao.list(entityClass,propertyName,value);
    }

    @Override
    @Transactional(readOnly = true)
    public List<T> listByOrder(String orderType, String orderName) {
        return baseDao.listByOrder(entityClass,orderType,orderName);
    }

    @Override
    @Transactional(readOnly = true)
    public List<T> list(DetachedCriteria detachedCriteria) {
        return baseDao.list(detachedCriteria);
    }

    @Override
    @Transactional(readOnly = true)
    public  List<T> listByCriterion(Criterion... criterions) {
        return baseDao.listByCriterion(entityClass,criterions);
    }

    @Override
    @Transactional(readOnly = true)
    public List<T> listByCriterion(String orderType, String orderName, Criterion... criterions) {
        return baseDao.listByCriterion(entityClass,orderType,orderName);
    }

    @Override
    @Transactional(readOnly = true)
    public List<T> listByCriterion(int page, int rows,Criterion... criterions) {
        return baseDao.listByCriterion(entityClass,page,rows,criterions);
    }

    @Override
    @Transactional(readOnly = true)
    public List<T> listByCriterion(int page, int rows, String orderType, String orderName, Criterion... criterions) {
        return baseDao.listByCriterion(entityClass,page,rows,orderType,orderName,criterions);
    }

    @Override
    @Transactional(readOnly = true)
    public List<T> list(int page, int rows, DetachedCriteria detachedCriteria) {
        return baseDao.list(page, rows, detachedCriteria);
    }

    @Override
    @Transactional(readOnly = true)
    public Page<T> list(Pageable pageable, DetachedCriteria detachedCriteria) {
        Long total = baseDao.count(detachedCriteria);
        List<T> content = list(pageable.getPageNumber(), pageable.getPageSize(), detachedCriteria);
        return new PageImpl<T>(content, pageable, total);
    }

    @Override
    @Transactional(readOnly = true)
    public Page<T> list(Queryable queryable, DetachedCriteria detachedCriteria) {
        QueryParse<DetachedCriteria> queryParse = new CriteriaParse();
        QueryableConvertUtils.convertQueryValueToEntityValue(queryable, entityClass);
        queryParse.parseCondition(detachedCriteria, queryable);
        Long total = baseDao.count(detachedCriteria);
        //排序问题
        queryParse.parseSort(detachedCriteria, queryable);
        Pageable pageable = queryable.getPageable();
        List<T> content = list(pageable.getPageNumber(), pageable.getPageSize(), detachedCriteria);
        return new PageImpl<T>(content, queryable.getPageable(), total);
    }

    @Override
    @Transactional(readOnly = true)
    public List<T> listWithNoPage(Queryable queryable, DetachedCriteria detachedCriteria) {
        QueryParse<DetachedCriteria> queryParse = new CriteriaParse();
        QueryableConvertUtils.convertQueryValueToEntityValue(queryable, entityClass);
        queryParse.parseCondition(detachedCriteria, queryable);
        queryParse.parseSort(detachedCriteria, queryable);
        return baseDao.list(detachedCriteria);
    }

    @Override
    public void remove(T entity) {
        baseDao.remove(entity);
    }

    @Override
    public void removeById(Serializable id) {
        baseDao.removeById(id,entityClass);
    }

    @Override
    public void removeAll(List<T> entitys) {
        baseDao.removeAll(entitys);
    }

    @Override
    public void removeAllById(List<?> ids) {
        for (Object id : ids) {
            baseDao.removeById((Serializable) id, entityClass);
        }
    }

    @Override
    public void removeAllByProperty(String propertyName, Object value) {
        baseDao.removeAllByProperty(propertyName,value,entityClass);
    }

    @Override
    public int updateByHql(String hql, Object... params) {
        return baseDao.updateByHql(hql,params);
    }

    @Override
    public int updateByAliasHql(String hql, Map<String, Object> alias) {
        return baseDao.updateByAliasHql(hql,alias);
    }

    @Override
    public Long countByHql(String hql, Object... params) {
        return baseDao.countByHql(hql,params);
    }

    @Override
    public Long countByAliasHql(String hql, Map<String, Object> alias) {
        return baseDao.countByAliasHql(hql,alias);
    }

    @Override
    @Transactional(readOnly = true)
    public  List<T> findByHql(String hql, Object... params) {
        return baseDao.findByHql(entityClass,hql,params);
    }

    @Override
    @Transactional(readOnly = true)
    public  List<T> findByAliasHql(String hql, Map<String, Object> alias) {
        return baseDao.findByAliasHql(hql,alias);
    }

    @Override
    @Transactional(readOnly = true)
    public  List<T> findByHql(String hql, int page, int rows, Object... params) {
        return baseDao.findByHql(hql,page,rows,params);
    }

    @Override
    @Transactional(readOnly = true)
    public List<T> findByAliasHql(String hql, int page, int rows, Map<String, Object> alias) {
        return baseDao.findByAliasHql(hql,page,rows,alias);
    }

    @Override
    public List<Map<String, Object>> findMapByHql(String hql, Object... params) {
        return baseDao.findMapByHql(hql,params);
    }

    @Override
    public List<Map<String, Object>> findMapByAliasHql(String hql, Map<String, Object> alias) {
        return baseDao.findMapByAliasHql(hql,alias);
    }

    @Override
    public Boolean doValid(DuplicateValid duplicateValid) {
        Boolean valid = Boolean.FALSE;
        String queryType = duplicateValid.getQueryType();
        if (StringUtils.isEmpty(queryType)) {
            queryType = QUERYTYPE_TABLE;
        }
        if (QUERYTYPE_TABLE.equals(queryType)) {
            valid = validTable(duplicateValid);
        }
        return valid;
    }

    private Boolean validTable(DuplicateValid duplicateValid) {
        Long num = null;
        String hql = "";
        String extendName = duplicateValid.getExtendName();
        String extendParam = duplicateValid.getExtendParam();
        if (!StringUtils.isEmpty(extendParam)) {
            // [2].编辑页面校验
            hql = "SELECT count(*) FROM " + entityClass.getName() + " as t WHERE t." + duplicateValid.getName() + " ='"
                    + duplicateValid.getParam() + "' and t." + extendName + " != '" + extendParam + "'";
            num = countByHql(hql);
        } else {
            // [1].添加页面校验
            hql = "SELECT count(*) FROM " + entityClass.getName() + " as t WHERE t." + duplicateValid.getName() + " ='"
                    + duplicateValid.getParam() + "'";
            num = countByHql(hql);
        }

        if (num == null || num == 0) {
            // 该值可用
            return true;
        } else {
            // 该值不可用
            return false;
        }
    }

    /**
     * 更新Redis缓存 单个对象
     * @param cahchekey
     * @param key
     * @param entity
     * @throws Exception
     */
    protected void updateCache(String cahchekey,String key, T entity)throws Exception{
        Map<String,T> allMap = (Map<String, T>) RedisUtils.getObject(cahchekey);
        if (allMap == null){
            allMap = new HashMap<String, T>(16);
        }
        allMap.put(key,entity);
        RedisUtils.setObject(cahchekey,allMap);
    }

    /**
     * 更新Redis缓存 map对象
     * @param cahchekey
     * @param map
     * @throws Exception
     */
    protected void updateBathCache(String cahchekey,Map<String,T> map)throws Exception{
        RedisUtils.setObject(cahchekey,map);
    }
}
